#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>

typedef unsigned long long  UINT64;
typedef unsigned short      UINT16;
typedef unsigned char       UINT8;

#define LS7A2000_SENSOR_CFG_OFFSET     0x0400
#define LS7A2000_SENSOR_TMP_OFFSET     0x0410
//#define LS7A2000_SENSOR_BASE_ADDR      0x5ffff000
#define LS7A2000_SENSOR_BASE_ADDR      0xe0010000000

#define LS3A5000_SENSOR_BASE_ADDR      0x1FE00000
#define LS3A5000_SENSOR_TMP_OFFSET     0x0198

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

UINT64
MemRead64(off_t target)
{
    int fd;
    void *map_base, *virt_addr; 
    unsigned long read_result, writeval;
    int access_type = 'w';

    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    fflush(stdout);

    /* Map one page */
    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
    if(map_base == (void *) -1) FATAL;
    //printf("Memory mapped at address %p.\n", map_base); 
    fflush(stdout);

    virt_addr = map_base + (target & MAP_MASK);
    switch(access_type) {
        case 'b':
            read_result = *((unsigned char *) virt_addr);
            break;
        case 'h':
            read_result = *((unsigned short *) virt_addr);
            break;
        case 'w':
            read_result = *((unsigned long *) virt_addr);
            break;
        default:
            fprintf(stderr, "Illegal data type '%c'.\n", access_type);
            exit(2);
    }
    //printf("Value at address 0x%lX (%p): 0x%lX\n", target, virt_addr, read_result); 
    fflush(stdout);

    if(munmap(map_base, MAP_SIZE) == -1) FATAL;
    close(fd);
    return read_result;
}

int main(int argc, char **argv) {

    UINT64            LS7A2000Temperature  = 0;
    UINT64            LS3A5000Temperature  = 0;
    UINT16            CPUTemperature0 = 0;
    UINT64            CPUTemperature0Mask = 0xFFFF00000000;
    UINT16            CPUTemperature1 = 0;
    UINT64            CPUTemperature1Mask = 0xFFFF000000000000;
    UINT64            ChipSetMask = 0xFF00000000000000;
    UINT8             ChipSetTemperature = 0;

    LS7A2000Temperature = MemRead64(LS7A2000_SENSOR_BASE_ADDR+LS7A2000_SENSOR_TMP_OFFSET);
    LS3A5000Temperature = MemRead64(LS3A5000_SENSOR_BASE_ADDR+LS3A5000_SENSOR_TMP_OFFSET);

    CPUTemperature0 = (LS3A5000Temperature & CPUTemperature0Mask) >> 32;
    CPUTemperature1 = (LS3A5000Temperature & CPUTemperature1Mask) >> 48;
    ChipSetTemperature = (LS7A2000Temperature & ChipSetMask) >> 56;
    printf("安徽百信龙芯平台温度读取工具V1.0\n");

    printf("CPU温度传感器0: %d\n", ((CPUTemperature0*731)/0x4000)-273);

    printf("CPU温度传感器1: %d\n", ((CPUTemperature1*731)/0x4000)-273);

    printf("桥片温度传感器: %d\n", ChipSetTemperature);

}
